﻿using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

namespace JPR.Common
{
	public static class Extensions
	{
		private const int CarriageReturn = 13;
		private const int LineFeed = 10;

		public static string ReadLine(this Stream data)
		{
			bool eol;
			List<byte> textBuffer = new List<byte>();
			int last = -1, current = -1;
			do
			{
				CheckIfValidValueAndAddToBuffer(textBuffer, last);
				last = current;
				current = data.ReadByte();
				if(current==-1)
				{
					throw new EndOfStreamException("Unexpected end of underlaying stream.");
				}
				eol = CheckEndOfLine(last, current);
			} while (!eol);
			return Encoding.ASCII.GetString(textBuffer.ToArray());
		}

		private static void CheckIfValidValueAndAddToBuffer(IList<byte> textBuffer, int last)
		{
			if (last >= 0)
			{
				textBuffer.Add((byte) last);
			}
		}

		private static bool CheckEndOfLine(int last, int current)
		{
			return last == CarriageReturn && current == LineFeed;
		}

		public static void WriteLine(this Stream stream)
		{
			WriteLine(stream, string.Empty);
		}

		public static void WriteLine(this Stream stream, string text)
		{
			byte[] data = Encoding.ASCII.GetBytes(text);
			stream.Write(data, 0, data.Length);
			stream.WriteByte(CarriageReturn);
			stream.WriteByte(LineFeed);
		}

		public static byte[] Serialize(this object obj)
		{
			BinaryFormatter formatter = new BinaryFormatter();
			MemoryStream stream = new MemoryStream();
			formatter.Serialize(stream, obj);
			stream.Seek(0, SeekOrigin.Begin);
			return stream.ToArray();
		}

		public static object Deserialize(this byte[] data)
		{
			MemoryStream memoryStream = new MemoryStream();
			memoryStream.Write(data, 0, data.Length);
			memoryStream.Seek(0, SeekOrigin.Begin);
			return Deserialize(memoryStream);
		}

		public static object Deserialize(this Stream stream)
		{
			BinaryFormatter formatter = new BinaryFormatter();
			return formatter.Deserialize(stream);
		}

		public static void ShiftLeft(this byte[] data, int shift)
		{
			for (int i = 0; i < data.Length - shift; i++)
			{
				data[i] = data[i + shift];
			}
		}

		public static void AppendLineBreak(this StringBuilder sb)
		{
			sb.Append("\r\n");
		}
	}
}